home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkError.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-13  |  8.6 KB  |  295 lines

  1. /* 
  2.  * tkError.c --
  3.  *
  4.  *    This file provides a high-performance mechanism for
  5.  *    selectively dealing with errors that occur in talking
  6.  *    to the X server.  This is useful, for example, when
  7.  *    communicating with a window that may not exist.
  8.  *
  9.  * Copyright 1990 Regents of the University of California.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkError.c,v 1.10 92/04/12 17:02:08 ouster Exp $ SPRITE (Berkeley)";
  21. #endif
  22.  
  23. #include "tkConfig.h"
  24. #include "tkInt.h"
  25.  
  26. static initialized = 0;
  27.  
  28. /*
  29.  * Forward references to procedures declared later in this file:
  30.  */
  31.  
  32. static int    ErrorProc _ANSI_ARGS_((Display *display,
  33.             XErrorEvent *errEventPtr));
  34.  
  35. /*
  36.  *--------------------------------------------------------------
  37.  *
  38.  * Tk_CreateErrorHandler --
  39.  *
  40.  *    Arrange for all a given procedure to be invoked whenever
  41.  *    certain errors occur.
  42.  *
  43.  * Results:
  44.  *    The return value is a token identifying the handler;
  45.  *    it must be passed to Tk_DeleteErrorHandler to delete the
  46.  *    handler.
  47.  *
  48.  * Side effects:
  49.  *    If an X error occurs that matches the error, request,
  50.  *    and minor arguments, then errorProc will be invoked.
  51.  *    ErrorProc should have the following structure:
  52.  *
  53.  *    int
  54.  *    errorProc(clientData, errorEventPtr)
  55.  *        caddr_t clientData;
  56.  *        XErrorEvent *errorEventPtr;
  57.  *    {
  58.  *    }
  59.  *
  60.  *    The clientData argument will be the same as the clientData
  61.  *    argument to this procedure, and errorEvent will describe
  62.  *    the error.  If errorProc returns 0, it means that it
  63.  *    completely "handled" the error:  no further processing
  64.  *    should be done.  If errorProc returns 1, it means that it
  65.  *    didn't know how to deal with the error, so we should look
  66.  *    for other error handlers, or invoke the default error
  67.  *    handler if no other handler returns zero.  Handlers are
  68.  *    invoked in order of age:  youngest handler first.
  69.  *
  70.  *    Note:  errorProc will only be called for errors associated
  71.  *    with X requests made AFTER this call, but BEFORE the handler
  72.  *    is deleted by calling Tk_DeleteErrorHandler.
  73.  *
  74.  *--------------------------------------------------------------
  75.  */
  76.  
  77. Tk_ErrorHandler
  78. Tk_CreateErrorHandler(display, error, request, minorCode, errorProc, clientData)
  79.     Display *display;        /* Display for which to handle
  80.                  * errors. */
  81.     int error;            /* Consider only errors with this
  82.                  * error_code (-1 means consider
  83.                  * all errors). */
  84.     int request;        /* Consider only errors with this
  85.                  * major request code (-1 means
  86.                  * consider all major codes). */
  87.     int minorCode;        /* Consider only errors with this
  88.                  * minor request code (-1 means
  89.                  * consider all minor codes). */
  90.     Tk_ErrorProc *errorProc;    /* Procedure to invoke when a
  91.                  * matching error occurs.  NULL means
  92.                  * just ignore matching errors. */
  93.     ClientData clientData;    /* Arbitrary value to pass to
  94.                  * errorProc. */
  95. {
  96.     register TkErrorHandler *errorPtr;
  97.     register TkDisplay *dispPtr;
  98.  
  99.     /*
  100.      * Make sure that X calls us whenever errors occur.
  101.      */
  102.  
  103.     if (!initialized) {
  104.     XSetErrorHandler(ErrorProc);
  105.     initialized = 1;
  106.     }
  107.  
  108.     /*
  109.      * Find the display.  If Tk doesn't know about this display,
  110.      * it's an error:  panic.
  111.      */
  112.  
  113.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  114.     if (dispPtr->display == display) {
  115.         break;
  116.     }
  117.     if (dispPtr == NULL) {
  118.         panic("Unknown display passed to Tk_CreateErrorHandler");
  119.     }
  120.     }
  121.  
  122.     /*
  123.      * Create the handler record.
  124.      */
  125.  
  126.     errorPtr = (TkErrorHandler *) ckalloc(sizeof(TkErrorHandler));
  127.     errorPtr->dispPtr = dispPtr;
  128.     errorPtr->firstRequest = NextRequest(display);
  129.     errorPtr->lastRequest = -1;
  130.     errorPtr->error = error;
  131.     errorPtr->request = request;
  132.     errorPtr->minorCode = minorCode;
  133.     errorPtr->errorProc = errorProc;
  134.     errorPtr->clientData = clientData;
  135.     errorPtr->nextPtr = dispPtr->errorPtr;
  136.     dispPtr->errorPtr = errorPtr;
  137.  
  138.     return (Tk_ErrorHandler) errorPtr;
  139. }
  140.  
  141. /*
  142.  *--------------------------------------------------------------
  143.  *
  144.  * Tk_DeleteErrorHandler --
  145.  *
  146.  *    Do not use an error handler anymore.
  147.  *
  148.  * Results:
  149.  *    None.
  150.  *
  151.  * Side effects:
  152.  *    The handler denoted by the "handler" argument will not
  153.  *    be invoked for any X errors associated with requests
  154.  *    made after this call.  However, if errors arrive later
  155.  *    for requests made BEFORE this call, then the handler
  156.  *    will still be invoked.  Call XSync if you want to be
  157.  *    sure that all outstanding errors have been received
  158.  *    and processed.
  159.  *
  160.  *--------------------------------------------------------------
  161.  */
  162.  
  163. void
  164. Tk_DeleteErrorHandler(handler)
  165.     Tk_ErrorHandler handler;    /* Token for handler to delete;
  166.                  * was previous return value from
  167.                  * Tk_CreateErrorHandler. */
  168. {
  169.     register TkErrorHandler *errorPtr = (TkErrorHandler *) handler;
  170.     register TkDisplay *dispPtr = errorPtr->dispPtr;
  171.  
  172.     errorPtr->lastRequest = NextRequest(dispPtr->display) - 1;
  173.  
  174.     /*
  175.      * Every once-in-a-while, cleanup handlers that are no longer
  176.      * active.  We probably won't be able to free the handler that
  177.      * was just deleted (need to wait for any outstanding requests to
  178.      * be processed by server), but there may be previously-deleted
  179.      * handlers that are now ready for garbage collection.  To reduce
  180.      * the cost of the cleanup, let a few dead handlers pile up, then
  181.      * clean them all at once.  This adds a bit of overhead to errors
  182.      * that might occur while the dead handlers are hanging around,
  183.      * but reduces the overhead of scanning the list to clean up
  184.      * (particularly if there are many handlers that stay around
  185.      * forever).
  186.      */
  187.  
  188.     dispPtr->deleteCount += 1;
  189.     if (dispPtr->deleteCount >= 10) {
  190.     register TkErrorHandler *prevPtr;
  191.     TkErrorHandler *nextPtr;
  192.     int lastSerial;
  193.  
  194.     dispPtr->deleteCount = 0;
  195.     lastSerial = LastKnownRequestProcessed(dispPtr->display);
  196.     errorPtr = dispPtr->errorPtr;
  197.     for (errorPtr = dispPtr->errorPtr, prevPtr = NULL;
  198.         errorPtr != NULL;  errorPtr = nextPtr) {
  199.         nextPtr = errorPtr->nextPtr;
  200.         if ((errorPtr->lastRequest != -1)
  201.             && (errorPtr->lastRequest <= lastSerial)) {
  202.         if (prevPtr == NULL) {
  203.             dispPtr->errorPtr = nextPtr;
  204.         } else {
  205.             prevPtr->nextPtr = nextPtr;
  206.         }
  207.         ckfree((char *) errorPtr);
  208.         continue;
  209.         }
  210.         prevPtr = errorPtr;
  211.     }
  212.     }
  213. }
  214.  
  215. /*
  216.  *--------------------------------------------------------------
  217.  *
  218.  * ErrorProc --
  219.  *
  220.  *    This procedure is invoked by the X system when error
  221.  *    events arrive.
  222.  *
  223.  * Results:
  224.  *    If it returns, the return value is zero.  However,
  225.  *    it is possible that one of the error handlers may
  226.  *    just exit.
  227.  *
  228.  * Side effects:
  229.  *    This procedure does two things.  First, it uses the
  230.  *    serial #  in the error event to eliminate handlers whose
  231.  *    expiration serials are now in the past.  Second, it
  232.  *    invokes any handlers that want to deal with the error.
  233.  *
  234.  *--------------------------------------------------------------
  235.  */
  236.  
  237. static int
  238. ErrorProc(display, errEventPtr)
  239.     Display *display;            /* Display for which error
  240.                      * occurred. */
  241.     register XErrorEvent *errEventPtr;    /* Information about error. */
  242. {
  243.     register TkDisplay *dispPtr;
  244.     register TkErrorHandler *errorPtr;
  245.     extern int _XDefaultError();
  246.  
  247.     /*
  248.      * See if we know anything about the display.  If not, then
  249.      * invoke the default error handler.
  250.      */
  251.  
  252.     for (dispPtr = tkDisplayList; ; dispPtr = dispPtr->nextPtr) {
  253.     if (dispPtr == NULL) {
  254.         goto couldntHandle;
  255.     }
  256.     if (dispPtr->display == display) {
  257.         break;
  258.     }
  259.     }
  260.  
  261.     /*
  262.      * Otherwise invoke any relevant handlers for the error, in order.
  263.      */
  264.  
  265.     for (errorPtr = dispPtr->errorPtr; errorPtr != NULL;
  266.         errorPtr = errorPtr->nextPtr) {
  267.     if ((errorPtr->firstRequest > errEventPtr->serial)
  268.         || ((errorPtr->error != -1)
  269.             && (errorPtr->error != errEventPtr->error_code))
  270.         || ((errorPtr->request != -1)
  271.             && (errorPtr->request != errEventPtr->request_code))
  272.         || ((errorPtr->minorCode != -1)
  273.             && (errorPtr->minorCode != errEventPtr->minor_code))
  274.         || ((errorPtr->lastRequest != -1)
  275.             && (errorPtr->lastRequest < errEventPtr->serial))) {
  276.         continue;
  277.     }
  278.     if (errorPtr->errorProc == NULL) {
  279.         return 0;
  280.     } else {
  281.         if ((*errorPtr->errorProc)(errorPtr->clientData,
  282.             errEventPtr) == 0) {
  283.         return 0;
  284.         }
  285.     }
  286.     }
  287.  
  288.     /*
  289.      * We couldn't handle the error.  Use the default handler.
  290.      */
  291.  
  292.     couldntHandle:
  293.     return _XDefaultError(display, errEventPtr);
  294. }
  295.